﻿#include "framework.h"
#include "Block.h"

// ████

// 全局变量
extern ColorGrid gExistentBlocks[GAME_BOARD_GRID_COUNT_V][GAME_BOARD_GRID_COUNT_H];

// 函数声明
static void Block2_EnterPreview(Block*, HDC);
static void Block2_Erase(Block*);
static int Block2_GetBottom(Block*);
static int Block2_GetTop(Block*);
static void Block2_HandleCannotMoveDown(Block*);
static BOOL Block2_MoveDown(Block*);
static void Block2_MoveLeft(Block*);
static void Block2_MoveRight(Block*);
static void Block2_Transform(Block*);

/**
 * 创建方块2。
 * @return 方块2
 */
Block* New_Block2() {
    int j = 0;

    // 创建方块
    Block* block = New_Block();

    // 初始化数据
    for (j = 0; j < BLOCK_GRID_COUNT_V; j++) {
        block->mBlocks[1][j].mUsed = TRUE;
    }

    // 初始化函数
    block->enterPreview = Block2_EnterPreview;
    block->erase = Block2_Erase;
    block->getBottom = Block2_GetBottom;
    block->getTop = Block2_GetTop;
    block->handleCannotMoveDown = Block2_HandleCannotMoveDown;
    block->moveDown = Block2_MoveDown;
    block->moveLeft = Block2_MoveLeft;
    block->moveRight = Block2_MoveRight;
    block->transform = Block2_Transform;

    return block;
}

/**
 * 进入预览区域。
 * @param block     方块2
 * @param drawer    绘图者
 */
static void Block2_EnterPreview(Block* block, HDC drawer) {
    int j = 0;
    RECT rect = { 0 };
    int x = PREVIEW_WIDTH / 2 - GRID_SIZE * 2;
    int y = (PREVIEW_HEIGHT - GRID_SIZE) / 2;

    for (j = 0; j < BLOCK_GRID_COUNT_H; j++) {
        rect.left = x + GRID_SIZE * j;
        rect.top = y;
        rect.right = rect.left + GRID_SIZE;
        rect.bottom = rect.top + GRID_SIZE;
        SetBkColor(drawer, block->mColor);
        ExtTextOut(drawer, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
        DrawEdge(drawer, &rect, EDGE_RAISED, BF_RECT);
    }
}

/**
 * 擦除。
 * @param block 方块2
 */
static void Block2_Erase(Block* block) {
    RECT rect = { 0 };

    switch (block->mShape) {
        case ONE:
            rect.left = GRID_SIZE * block->mLine;
            rect.top = GRID_SIZE * (block->mRow + 1);
            rect.right = rect.left + GRID_SIZE * 4;
            rect.bottom = rect.top + GRID_SIZE;
            break;
        case TWO:
            rect.left = GRID_SIZE * (block->mLine + 1);
            rect.top = GRID_SIZE * block->mRow;
            rect.right = rect.left + GRID_SIZE;
            rect.bottom = rect.top + GRID_SIZE * 4;
            break;
    }
    block->eraseRect(block, &rect);
}

/**
 * 获取底端所在的行数。底端是指方块最下方的有效格。
 * @param block 方块2
 * @return 底端所在的行数
 */
static int Block2_GetBottom(Block* block) {
    if (block->mShape == ONE) {
        return block->mRow + 1;
    }
    return block->mRow + 3;
}

/**
 * 获取顶端所在的行数。顶端是指方块最上方的有效格。
 * @param block 方块2
 * @return 顶端所在的行数
 */
static int Block2_GetTop(Block* block) {
    if (block->mShape == ONE) {
        return block->mRow + 1;
    }
    return block->mRow;
}

/**
 * 对不能下落的处理。
 * @param block 方块2
 */
static void Block2_HandleCannotMoveDown(Block* block) {
    int i = 0, j = 0;
    switch (block->mShape) {
        case ONE:
            for (j = 0; j < BLOCK_GRID_COUNT_H; j++) {
                gExistentBlocks[block->mRow + 1][block->mLine + j].mUsed = TRUE;
                gExistentBlocks[block->mRow + 1][block->mLine + j].mColor = block->mColor;
            }
            break;
        case TWO:
            for (i = 0; i < BLOCK_GRID_COUNT_V; i++) {
                gExistentBlocks[block->mRow + i][block->mLine + 1].mUsed = TRUE;
                gExistentBlocks[block->mRow + i][block->mLine + 1].mColor = block->mColor;
            }
            break;
    }
}

/**
 * 下落。
 * @param block 方块2
 * @return 成功则返回 TRUE，否则返回 FALSE
 */
static BOOL Block2_MoveDown(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mRow == 18) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            for (int i = 0; i < BLOCK_GRID_COUNT_H; i++) {
                if (gExistentBlocks[block->mRow + 2][block->mLine + i].mUsed) {
                    block->handleCannotMoveDown(block);
                    return FALSE;
                }
            }
            break;
        case TWO:
            if (block->mRow == 16) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            if (gExistentBlocks[block->mRow + 4][block->mLine + 1].mUsed) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            break;
    }

    return Block_MoveDown(block);
}

/**
 * 左移。
 * @param block 方块2
 */
static void Block2_MoveLeft(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mLine == 0) {
                return;
            }
            if (gExistentBlocks[block->mRow + 1][block->mLine - 1].mUsed) {
                return;
            }
            break;
        case TWO:
            if (block->mLine == -1) {
                return;
            }
            for (int i = 0; i < BLOCK_GRID_COUNT_V; i++) {
                if (gExistentBlocks[block->mRow + i][block->mLine].mUsed) {
                    return;
                }
            }
            break;
    }

    Block_MoveLeft(block);
}

/**
 * 右移。
 * @param block 方块2
 */
static void Block2_MoveRight(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mLine == 6) {
                return;
            }
            if (gExistentBlocks[block->mRow + 1][block->mLine + 4].mUsed) {
                return;
            }
            break;
        case TWO:
            if (block->mLine == 8) {
                return;
            }
            for (int i = 0; i < BLOCK_GRID_COUNT_V; i++) {
                if (gExistentBlocks[block->mRow + i][block->mLine + 2].mUsed) {
                    return;
                }
            }
            break;
    }

    Block_MoveRight(block);
}

/**
 * 变形。
 * @param block 方块2
 */
static void Block2_Transform(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mRow == -1 || block->mRow >= 17) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine + 1].mUsed ||
                gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed ||
                gExistentBlocks[block->mRow + 3][block->mLine + 1].mUsed) {
                return;
            }
            block->erase(block);
            block->mBlocks[1][0].mUsed = block->mBlocks[1][2].mUsed = block->mBlocks[1][3].mUsed = FALSE;
            block->mBlocks[0][1].mUsed = block->mBlocks[2][1].mUsed = block->mBlocks[3][1].mUsed = TRUE;
            block->mShape = TWO;
            break;
        case TWO:
            if (block->mLine == -1 || block->mLine >= 7) {
                return;
            }
            if (gExistentBlocks[block->mRow + 1][block->mLine].mUsed ||
                gExistentBlocks[block->mRow + 1][block->mLine + 2].mUsed ||
                gExistentBlocks[block->mRow + 1][block->mLine + 3].mUsed) {
                return;
            }
            block->erase(block);
            block->mBlocks[1][0].mUsed = block->mBlocks[1][2].mUsed = block->mBlocks[1][3].mUsed = TRUE;
            block->mBlocks[0][1].mUsed = block->mBlocks[2][1].mUsed = block->mBlocks[3][1].mUsed = FALSE;
            block->mShape = ONE;
            break;
    }

    Block_Draw(block);
}
